package com.blue.http.message;

import java.util.concurrent.TimeUnit;

import com.blue.http.filter.SessionCookieFilter;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;

/**
 * @author zhengjin
 * @since 1.0 2018年04月10日
 */
public class HttpSession
{
	//private static Logger logger = LoggerFactory.getLogger(HttpSession.class);
	public static final int EXPIRE = 7200;
	public static final String SESSION_KEY = "com.blue.http.session:";
	private static final String SESSION_USER_KEY = "com.blue.http.session.user:";
	private static final String ATTRIBUTE = "ATTRIBUTE:";
	private static final String ATTRIBUTE_USER = "ATTRIBUTE.USER";

	private SessionUserListener sessionUserListener;
	private boolean fire = false;
	private int expire = EXPIRE;
	protected RedisTemplate<String, Object> redisTemplate;
	
	public static enum Operation
	{
		NONE, OP_EXPIRE
	}

	public HttpSession(RedisTemplate<String, Object> redisTemplate)
	{
		this.redisTemplate = redisTemplate;
	}

	/**
	 * 获取会话中的属性值
	 */
	public Object getAttribute(HttpRequest request, String name)
	{
		BoundHashOperations<String, String, Object> hashOp = this.getHashOp(request, Operation.OP_EXPIRE);
		if (hashOp == null)
			return null;

		Object object = hashOp.get(ATTRIBUTE + name);
		this.getValueOp(hashOp.get(ATTRIBUTE_USER), Operation.OP_EXPIRE);
		return object;
	}

	/**
	 * 设置会话中的属性
	 */
	public void setAttribute(HttpRequest request, String name, Object value)
	{
		if (value == null || "".equals(value))
		{
			this.removeAttribute(request, name);
			return;
		}

		BoundHashOperations<String, String, Object> hashOp = this.getHashOp(request, Operation.OP_EXPIRE);
		if (hashOp == null)
			return;

		hashOp.put(ATTRIBUTE + name, value);
		if (value instanceof SessionUser)
		{
			SessionUser user = (SessionUser) value;
			hashOp.put(ATTRIBUTE_USER, user);
		}

		BoundValueOperations<String, Object> valueOp = this.getValueOp(value, Operation.OP_EXPIRE);
		if (valueOp != null)
		{
			String token1 = (String) valueOp.get();
			String token2 = this.getSession(request);
			if (token1 != null && !token1.isEmpty() && token2 != null && !token2.isEmpty() && !token1.equals(token2))
			{
				String key = SESSION_USER_KEY + token1;
				redisTemplate.delete(key);
				if (sessionUserListener != null)
				{
					sessionUserListener.fired(token1, (SessionUser)value);
				}
			}

			valueOp.set(token2);
		}
	}

	/**
	 * 删除会话中的属性
	 */
	public void removeAttribute(HttpRequest request, String name)
	{
		if (name == null || name.isEmpty())
			return;

		BoundHashOperations<String, String, Object> hashOp = this.getHashOp(request, Operation.OP_EXPIRE);
		if (hashOp == null)
			return;

		hashOp.delete(ATTRIBUTE + name);
		this.getValueOp(hashOp.get(ATTRIBUTE_USER), Operation.OP_EXPIRE);
	}

	/**
	 * 删除会话
	 */
	public void delete(HttpRequest request)
	{
		if (fire)
		{
			BoundHashOperations<String, String, Object> hashOp = this.getHashOp(request, Operation.OP_EXPIRE);
			if (hashOp == null)
				return;

			Object object = hashOp.get(ATTRIBUTE_USER);
			if (object != null && object instanceof SessionUser)
			{
				String key = SESSION_USER_KEY + ((SessionUser)object).getKey();
				redisTemplate.delete(key);
			}
		}

		String token = this.getSession(request);
		if (token != null && !token.isEmpty())
		{
			String key = SESSION_KEY + token;
			redisTemplate.delete(key);
		}
	}

	/**
	 * 获取redis操作入口
	 *
	 * @param op 操作方式
	 * @return
	 */
	protected BoundHashOperations<String, String, Object> getHashOp(HttpRequest request, Operation op)
	{
		String token = this.getSession(request);
		if (token == null || token.isEmpty())
			return null;

		String key = SESSION_KEY + token;
		BoundHashOperations<String, String, Object> hashOp = redisTemplate.boundHashOps(key);

		if (op != null && op == Operation.OP_EXPIRE)
		{
			redisTemplate.expire(key, expire, TimeUnit.SECONDS);
		}
		return hashOp;
	}
	
	/**
	 * 获取redis接作入口
	 * 
	 * @param object 对象
	 * @param op 操作方式
	 * @return
	 */
	protected BoundValueOperations<String, Object> getValueOp(Object object, Operation op)
	{
		if (!fire || object == null || !(object instanceof SessionUser))
			return null;
		
		SessionUser user = (SessionUser)object;
		String key = SESSION_USER_KEY + user.getKey();
		BoundValueOperations<String, Object> valueOp = redisTemplate.boundValueOps(key);
		
		if (op != null && op == Operation.OP_EXPIRE)
		{
			redisTemplate.expire(key, expire, TimeUnit.SECONDS);
		}
		
		return valueOp;
	}

	protected String getSession(HttpRequest request)
	{
		String session = request.getQueryString(SessionCookieFilter.SESSION);
		if (session == null || session.isEmpty())
			session = request.getCookie(SessionCookieFilter.SESSION);

		return session;
	}

	public void setExpire(int expire)
	{
		this.expire = expire;
	}

	public void setFire(boolean fire)
	{
		this.fire = fire;
	}

	public void setSessionUserListener(SessionUserListener sessionUserListener)
	{
		this.sessionUserListener = sessionUserListener;
	}
}
